package com.company.cloud.mall.modules.app.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.company.cloud.acct.modules.api.constant.AcctOpTypeEnum;
import com.company.cloud.acct.modules.api.constant.AcctTypeEnum;
import com.company.cloud.acct.modules.api.request.AcctOpRequest;
import com.company.cloud.acct.modules.api.service.AccountRemoteService;
import com.company.cloud.common.asserts.ValidatorUtils;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.constant.BaseConstant.YNEnum;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.utils.CheckUtils;
import com.company.cloud.common.utils.StrSplitUtils;
import com.company.cloud.mall.constant.MallErrorEnum;
import com.company.cloud.mall.constant.PayMethodEnum;
import com.company.cloud.mall.constant.ShopConstant.PayActionTypeEnum;
import com.company.cloud.mall.constant.ShopConstant.PayConfirmWay;
import com.company.cloud.mall.modules.api.constant.OrderRefundStateEnum;
import com.company.cloud.mall.modules.api.constant.OrderStateEnum;
import com.company.cloud.mall.modules.api.response.OrderRefundsModel;
import com.company.cloud.mall.modules.app.controller.req.OrderRefundsApplyParam;
import com.company.cloud.mall.modules.app.service.ShopAfterSaleRefundsService;
import com.company.cloud.mall.modules.app.service.ShopOnlinePayService;
import com.company.cloud.mall.modules.app.utils.AfterOrderUtil;
import com.company.cloud.mall.modules.base.entity.OrderInfo;
import com.company.cloud.mall.modules.base.entity.OrderItem;
import com.company.cloud.mall.modules.base.entity.OrderLog;
import com.company.cloud.mall.modules.base.entity.OrderPayment;
import com.company.cloud.mall.modules.base.entity.OrderRefunds;
import com.company.cloud.mall.modules.base.entity.OrderReturns;
import com.company.cloud.mall.modules.base.service.OrderInfoService;
import com.company.cloud.mall.modules.base.service.OrderItemService;
import com.company.cloud.mall.modules.base.service.OrderLogService;
import com.company.cloud.mall.modules.base.service.OrderPaymentService;
import com.company.cloud.mall.modules.base.service.OrderRefundsService;
import com.company.cloud.mall.modules.base.service.OrderReturnsService;
import com.company.cloud.mall.modules.bus.producer.ShopOrderProducer;
import com.company.cloud.mall.modules.mgr.controller.req.OrderRefundCheckParam;
import com.company.cloud.mall.modules.utils.ShopNoUtils;
import com.company.cloud.mall.modules.utils.ShopOrderConvertUtils;
import com.company.cloud.pay.modules.api.constant.PayRefundStateEnum;
import com.company.cloud.pay.modules.api.constant.PayStateEnum;
import com.company.common.server.constant.IRelBusiType;

import cn.hutool.core.date.DateUtil;

/**
 * 订单退款
 */
@Service
public class ShopAfterSaleRefundsServiceImpl implements ShopAfterSaleRefundsService {


    @Autowired
    private OrderRefundsService orderRefundsService;
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderLogService orderLogService;
    @Autowired
    private OrderReturnsService orderReturnsService;
    @Autowired
    private OrderPaymentService orderPaymentService;
    @Autowired
    private AccountRemoteService accountRemoteService;
    @Autowired
    private ShopOnlinePayService shopOnlinePayService;
    @Autowired
    private ShopOrderProducer shopOrderProducer;

    /**
     * 新增
     */
    @Transactional
    @Override
    public void add(OrderRefundsApplyParam params, LoginSimpleUserInfo userInfo) {
        ValidatorUtils.validate(params);
        OrderItem orderItem = orderItemService.getById(params.getOrderItemId());
        if (null == orderItem) {
            throw new BusinessException(MallErrorEnum.Order_Item_Null);
        }
        if (YNEnum.NO.getCode().equals(orderItem.getIsExchangePurchase())) {
            throw new BusinessException(MallErrorEnum.Order_After_Product_Not);
        }
        OrderInfo order = orderInfoService.getById(orderItem.getOrderSn());
        if (null == order) {
            throw new BusinessException(MallErrorEnum.Order_Null);
        }
        if (userInfo.getId().intValue() != order.getUserId().intValue()) {
            throw new BusinessException(MallErrorEnum.Order_After_User_Error);
        }
        if (OrderStateEnum.OSE_Pay.getCode().equals(order.getStatus())
                || OrderStateEnum.OSE_Close.getCode().equals(order.getStatus())) {
            throw new BusinessException(MallErrorEnum.Order_After_Not);
        }

        //判断退款金额
        BigDecimal reFund = order.getFund().subtract(order.getRefundFund());
        if (params.getFund().doubleValue() > reFund.doubleValue()) {
            throw new BusinessException(MallErrorEnum.Order_After_Fund);
        }

        List<OrderRefunds> orderRefundsList = orderRefundsService.list(new QueryWrapper<OrderRefunds>()
                .eq("order_sn", orderItem.getOrderSn())
                .eq("order_item_id", orderItem.getId()));
        List<OrderReturns> orderReturnsList = orderReturnsService.list(new QueryWrapper<OrderReturns>()
                .eq("order_sn", orderItem.getOrderSn())
                .eq("order_item_id", orderItem.getId()));

        if (!AfterOrderUtil.validateOrderIng(orderRefundsList, orderReturnsList)) {
            throw new BusinessException(MallErrorEnum.Order_After_Ing);
        }

        OrderRefunds refunds = new OrderRefunds();
        refunds.setSn(ShopNoUtils.getOrderRefund());
        refunds.setCompanyNo(order.getCompanyNo());
        refunds.setMainCompanyNo(order.getMainCompanyNo());
        refunds.setUserId(order.getUserId());
        refunds.setOrderSn(order.getSn());
        refunds.setOrderItemId(orderItem.getId());
        refunds.setProductNo(orderItem.getProductNo());
        refunds.setMainProductNo(orderItem.getMainProductNo());
        refunds.setSkuNo(orderItem.getSkuNo());
        refunds.setMainSkuNo(orderItem.getMainSkuNo());
        refunds.setName(orderItem.getName());
        refunds.setThumbnail(orderItem.getThumbnail());
        refunds.setSpecifications(orderItem.getSpecifications());
        refunds.setProductState(params.getProductState());
        refunds.setReason(params.getReason());
        refunds.setFund(params.getFund());
        refunds.setMemo(params.getMemo());
        refunds.setCertificate(StrSplitUtils.list2string(params.getCertificate()));
        refunds.setState(OrderRefundStateEnum.ORFS_Apply.getCode());
        refunds.setStartDate(LocalDateTime.now());
        refunds.addCreateParam(userInfo);
        orderRefundsService.save(refunds);

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.setMemo(refunds.getMemo());
        log.addCreateParam(userInfo);
        orderLogService.save(log);

        order.setRefundFund(order.getRefundFund().add(params.getFund()));
        order.addEditParam(userInfo);
        orderInfoService.updateById(order);
        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }

    /**
     * 撤销
     */
    @Transactional
    @Override
    public void cancel(String sn, LoginSimpleUserInfo userInfo) {
        OrderRefunds refunds = orderRefundsService.getById(sn);
        if (null == refunds) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }
        if (userInfo.getId().intValue() != refunds.getUserId().intValue()) {
            throw new BusinessException(MallErrorEnum.Order_After_User_Error);
        }
        if (OrderRefundStateEnum.ORFS_Refund.getCode().equals(refunds.getState())
                || OrderRefundStateEnum.ORFS_Complete.getCode().equals(refunds.getState())) {
            throw new BusinessException(MallErrorEnum.Order_State_Op_Not);
        }
        refunds.setState(OrderRefundStateEnum.ORFS_Cancel.getCode());
        refunds.setEndDate(LocalDateTime.now());
        refunds.setHandleUserId(userInfo.getId());
        refunds.setHandleDate(LocalDateTime.now());
        refunds.addEditParam(userInfo);
        orderRefundsService.updateById(refunds);

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.addCreateParam(userInfo);
        orderLogService.save(log);

        OrderInfo order = orderInfoService.getById(refunds.getOrderSn());
        order.setRefundFund(order.getRefundFund().subtract(refunds.getFund()));
        order.addEditParam(userInfo);
        orderInfoService.updateById(order);
        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }

    /**
     * 审核
     */
    @Transactional
    @Override
    public void check(OrderRefundCheckParam params, LoginSimpleUserInfo userInfo) {
        OrderRefunds refunds = orderRefundsService.getById(params.getSn());
        if (null == refunds) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }
        if (!userInfo.getCompanyNo().equals(refunds.getMainCompanyNo())) {
            throw new BusinessException(MallErrorEnum.Order_After_User_Error);
        }
        if (!OrderRefundStateEnum.ORFS_Apply.getCode().equals(refunds.getState())) {
            throw new BusinessException(MallErrorEnum.Order_State_Op_Not);
        }
        if (YNEnum.YES.getCode().equals(params.getStatus())) {
            if (!CheckUtils.hasInt(params.getQuantity())) {
                throw new BusinessException(BaseReturnEnum.PARAM_NULL);
            }
            OrderItem orderItem = orderItemService.getById(refunds.getOrderItemId());

            Integer returnNum = orderItem.getReturnedQuantity() + params.getQuantity();
            if (returnNum.intValue() > orderItem.getQuantity().intValue()) {
                throw new BusinessException("退款数量不能大于订单商品数量");
            }
            if (StringUtils.hasText(params.getIsSend())
                    && YNEnum.NO.getCode().equals(params.getIsSend())) {
                Integer returnNotSendNum = orderItem.getReturnedNotSendQuantity() + params.getQuantity();
                orderItem.setReturnedNotSendQuantity(returnNotSendNum);
            }
            orderItem.setReturnedQuantity(returnNum);
            orderItem.addEditParam(userInfo);
            orderItemService.updateById(orderItem);

            refunds.setState(OrderRefundStateEnum.ORFS_Check_Success.getCode());
            refunds.setQuantity(params.getQuantity());
        } else if (YNEnum.NO.getCode().equals(params.getStatus())) {
            refunds.setState(OrderRefundStateEnum.ORFS_Check_Fail.getCode());
        }

        refunds.setRemark(params.getMemo());
        refunds.setEndDate(LocalDateTime.now());
        refunds.setHandleUserId(userInfo.getId());
        refunds.setHandleDate(LocalDateTime.now());
        refunds.addEditParam(userInfo);
        orderRefundsService.updateById(refunds);

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.setMemo(params.getMemo());
        log.addCreateParam(userInfo);
        orderLogService.save(log);

        if (YNEnum.NO.getCode().equals(params.getStatus())) {
            OrderInfo order = orderInfoService.getById(refunds.getOrderSn());
            order.setRefundFund(order.getRefundFund().subtract(refunds.getFund()));
            order.addEditParam(userInfo);
            orderInfoService.updateById(order);
        }
        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }

    /**
     * 退款(退款申请)
     */
    @Transactional
    @Override
    public void refund(String sn, LoginSimpleUserInfo userInfo) {
        OrderRefunds refunds = orderRefundsService.getById(sn);
        if (null == refunds) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }
        if (!userInfo.getCompanyNo().equals(refunds.getMainCompanyNo())) {
            throw new BusinessException(MallErrorEnum.Order_After_User_Error);
        }
        if (OrderRefundStateEnum.ORFS_Check_Success.getCode().equals(refunds.getState())
                || OrderRefundStateEnum.ORFS_RefundFail.getCode().equals(refunds.getState())) {
        } else {
            throw new BusinessException(MallErrorEnum.Order_State_Op_Not);
        }

        OrderInfo orderInfo = orderInfoService.getById(refunds.getOrderSn());
        if (null == orderInfo) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }

        //资金原路返回
        //线上支付
        if (PayMethodEnum.PM_Online_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            OrderPayment orderPayment = orderPaymentService.getOne(new QueryWrapper<OrderPayment>()
                    .eq("type", PayActionTypeEnum.PA_Pay.getCode())
                    .eq("biz_order_type", IRelBusiType.Order_ObjType)
                    .eq("biz_order_sn", refunds.getOrderSn())
                    .eq("payment_state", PayStateEnum.Pay_Success.getCode())
            );
            if (orderPayment != null) {
                if (PayMethodEnum.PM_Online_Pay.getCode().equals(orderPayment.getPaymentMethod())) {
                    OrderPayment refundPayment = new OrderPayment();
                    refundPayment.setType(PayActionTypeEnum.PA_Refund.getCode());
                    refundPayment.setPaySn(ShopNoUtils.getRefundSn());
                    refundPayment.setBizOrderType(IRelBusiType.Order_Refunds_ObjType);
                    refundPayment.setBizOrderSn(refunds.getSn());
                    refundPayment.setCustNo(refunds.getCompanyNo());
                    refundPayment.setPayerUserId(refunds.getUserId());
                    refundPayment.setPaymentMethod(orderPayment.getPaymentMethod());
                    refundPayment.setPaymentChannel(orderPayment.getPaymentChannel());
                    refundPayment.setFund(refunds.getFund());
                    refundPayment.setFee(BigDecimal.ZERO);
                    refundPayment.setTotalFund(refundPayment.getFund().add(refundPayment.getFee()));
                    refundPayment.setPaymentState(PayRefundStateEnum.Refund_Ing.getCode());
                    refundPayment.setPaymentApplyDate(LocalDateTime.now());
                    refundPayment.setCheckState(YNEnum.NO.getCode());
                    refundPayment.addCreateParam(userInfo);
                    orderPaymentService.save(refundPayment);
                    shopOnlinePayService.payRefundApply(refunds.getCompanyNo(), refundPayment.getPaymentChannel(), orderPayment.getPaySn(), orderPayment.getTotalFund(), refundPayment.getPaySn(), refunds.getFund(), "");
                }
            }
        } else if (PayMethodEnum.PM_Point_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            //积分支付-退款
            AcctOpRequest pointParams = new AcctOpRequest();
            pointParams.setUserId(refunds.getUserId());
            pointParams.setType(AcctTypeEnum.Point_Acct.getCode());
            pointParams.setIsAcctDetail(YNEnum.YES.getCode());
            pointParams.setOpType(AcctOpTypeEnum.Add_Acct.getCode());
            pointParams.setRelObjType(IRelBusiType.Order_Refunds_ObjType);
            pointParams.setRelObjNo(refunds.getSn());
            pointParams.setFundOp(refunds.getFund());
            pointParams.setFundTax(BigDecimal.ZERO);
            pointParams.setRelBizName(refunds.getName());
            pointParams.setRelDate(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            pointParams.setBusiType("订单退款");
            pointParams.setMemo("退款");
            pointParams.setOpUserId(userInfo.getId());
            pointParams.setOpIp(userInfo.getIp());
            accountRemoteService.opAcct(pointParams);
        } else if (PayMethodEnum.PM_Acct_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            //账户支付
            //todo
        }

        if (PayMethodEnum.PM_Online_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            refunds.setState(OrderRefundStateEnum.ORFS_Refund.getCode());
        } else if (PayMethodEnum.PM_Point_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            refunds.setState(OrderRefundStateEnum.ORFS_Complete.getCode());
            refunds.setEndDate(LocalDateTime.now());
        } else if (PayMethodEnum.PM_Acct_Pay.getCode().equals(orderInfo.getPaymentMethod())) {
            //账户支付
            //todo
        }
        refunds.setEndDate(LocalDateTime.now());
        refunds.setHandleUserId(userInfo.getId());
        refunds.setHandleDate(LocalDateTime.now());
        refunds.addEditParam(userInfo);
        orderRefundsService.updateById(refunds);

        //判断订单是否全部退款
        if (OrderRefundStateEnum.ORFS_Complete.getCode().equals(refunds.getState())) {
            this.checkReturnFull(refunds.getOrderSn(), userInfo);
        }

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.addCreateParam(userInfo);
        orderLogService.save(log);

        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }

    /**
     * 第三方支付退款回调处理
     */
    @Transactional
    @Override
    public void callbackRefund(String sn, String refundSN, String refundState, String thirdrefundState,
                               PayConfirmWay confirmChannel, LoginSimpleUserInfo userInfo) {
        OrderPayment orderPayment = orderPaymentService.getOne(new QueryWrapper<OrderPayment>()
                .eq("pay_sn", refundSN));
        if (orderPayment == null) {
            throw new BusinessException(BaseReturnEnum.DATA_NOT_EXISTS);
        }

        //支付流水
        if (StringUtils.isEmpty(orderPayment.getPaymentConfirmChannel())
                || confirmChannel.getCode().equals(orderPayment.getPaymentConfirmChannel())
                || Integer.parseInt(confirmChannel.getCode()) > Integer.parseInt(orderPayment.getPaymentConfirmChannel())
        ) {
            orderPayment.setPaymentState(refundState);
            orderPayment.setPaymentConfirmDate(LocalDateTime.now());
            orderPayment.setPaymentConfirmChannel(confirmChannel.getCode());
            orderPayment.setThirdState(thirdrefundState);
            orderPayment.addEditParam(userInfo);
            orderPaymentService.updateById(orderPayment);
        } else {
            return;
        }

        OrderRefunds refunds = orderRefundsService.getById(sn);
        if (null == refunds) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }

//		if(!OrderRefundStateEnum.ORFS_Refund.getCode().equals(refunds.getState())   ) {
//			throw new BusinessException(ShopErrorEnum.Order_State_Op_Not);
//		}

        //退款
        if (PayRefundStateEnum.Refund_Success.getCode().equals(orderPayment.getPaymentState())) {
            refunds.setState(OrderRefundStateEnum.ORFS_Complete.getCode());
            refunds.setEndDate(LocalDateTime.now());
        }
        if (PayRefundStateEnum.Refund_Fail.getCode().equals(orderPayment.getPaymentState())
                || PayRefundStateEnum.Refund_Close.getCode().equals(orderPayment.getPaymentState())) {
            refunds.setState(OrderRefundStateEnum.ORFS_RefundFail.getCode());
        }
        refunds.setHandleUserId(userInfo.getId());
        refunds.setHandleDate(LocalDateTime.now());
        refunds.addEditParam(userInfo);
        orderRefundsService.updateById(refunds);

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.addCreateParam(userInfo);
        orderLogService.save(log);
        //判断订单是否全部退款
        if (OrderRefundStateEnum.ORFS_Complete.getCode().equals(refunds.getState())) {
            this.checkReturnFull(refunds.getOrderSn(), userInfo);
        }

        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }


    /**
     * 退款完成
     */
    @Override
    public void complete(String sn, LoginSimpleUserInfo userInfo) {
        OrderRefunds refunds = orderRefundsService.getById(sn);
        if (null == refunds) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }
        if (!OrderRefundStateEnum.ORFS_Refund.getCode().equals(refunds.getState())) {
            throw new BusinessException(MallErrorEnum.Order_State_Op_Not);
        }
        refunds.setState(OrderRefundStateEnum.ORFS_Complete.getCode());
        refunds.setEndDate(LocalDateTime.now());
        refunds.setHandleUserId(userInfo.getId());
        refunds.setHandleDate(LocalDateTime.now());
        refunds.addEditParam(userInfo);
        orderRefundsService.updateById(refunds);

        OrderLog log = new OrderLog();
        log.setOrderType(IRelBusiType.Order_Refunds_ObjType);
        log.setSn(refunds.getSn());
        log.setState(refunds.getState());
        log.addCreateParam(userInfo);
        orderLogService.save(log);
        //判断订单是否全部退款
        this.checkReturnFull(refunds.getOrderSn(), userInfo);

        //MQ
        shopOrderProducer.onRefundsOrderChange(refunds);
    }

    /**
     * 判断订单是否全部退款
     */
    private void checkReturnFull(String orderSN, LoginSimpleUserInfo userInfo) {
        int count = orderItemService.count(new QueryWrapper<OrderItem>()
                .eq("order_sn", orderSN)
                .apply("quantity <> returned_quantity")
        );
        if (count == 0) {
            OrderInfo order = orderInfoService.getById(orderSN);
            order.setStatus(OrderStateEnum.OSE_Close.getCode());
            order.setCloseDate(LocalDateTime.now());
            order.setHandleDate(LocalDateTime.now());
            order.setHandleUserId(userInfo.getId());
            order.addEditParam(userInfo);
            orderInfoService.updateById(order);
        }
    }


    /**
     * 获取
     */
    @Override
    public OrderRefundsModel get(String sn) {
        OrderRefunds entity = orderRefundsService.getById(sn);
        if (entity == null) {
            throw new BusinessException(MallErrorEnum.Order_After_Refunds_NotExist);
        }
//		List<OrderLog> records=orderLogService.list(new QueryWrapper<OrderLog>()
//				.eq("order_type", ShopObjType.Order_Refunds_ObjType).eq("sn", sn).orderByAsc("cdt"));
        return ShopOrderConvertUtils.getOrderRefunds(entity, null, null);
    }


}
